package com.fresh.auth0.algorithms;

import com.fresh.auth0.exceptions.SignatureGenerationException;
import com.fresh.auth0.exceptions.SignatureVerificationException;

import java.io.UnsupportedEncodingException;
import java.security.interfaces.ECKey;
import java.security.interfaces.RSAKey;

/**
 * 创建token相关算法
 */
public abstract class Algorithm {

    private final String name;
    private final String description;

    /**
     * RS256 算法
     * @param key
     * @return
     * @throws IllegalArgumentException
     */
    public static Algorithm RSA256(RSAKey key) throws IllegalArgumentException {
        return new RSAAlgorithm("RS256", "SHA256withRSA", key);
    }

    /**
     * RS384 算法
     * @param key
     * @return
     * @throws IllegalArgumentException
     */
    public static Algorithm RSA384(RSAKey key) throws IllegalArgumentException {
        return new RSAAlgorithm("RS384", "SHA384withRSA", key);
    }

    /**
     * RS512 算法
     * @param key
     * @return
     * @throws IllegalArgumentException
     */
    public static Algorithm RSA512(RSAKey key) throws IllegalArgumentException {
        return new RSAAlgorithm("RS512", "SHA512withRSA", key);
    }

    /**
     * HS256 算法
     * @param key
     * @return
     * @throws IllegalArgumentException
     */
    public static Algorithm HMAC256(String secret) throws IllegalArgumentException, UnsupportedEncodingException {
        return new HMACAlgorithm("HS256", "HmacSHA256", secret);
    }

    /**
     * HS384 算法
     * @param key
     * @return
     * @throws IllegalArgumentException
     */
    public static Algorithm HMAC384(String secret) throws IllegalArgumentException, UnsupportedEncodingException {
        return new HMACAlgorithm("HS384", "HmacSHA384", secret);
    }

    /**
     * HS512 算法
     * @param key
     * @return
     * @throws IllegalArgumentException
     */
    public static Algorithm HMAC512(String secret) throws IllegalArgumentException, UnsupportedEncodingException {
        return new HMACAlgorithm("HS512", "HmacSHA512", secret);
    }

    /**
     * HS256 算法
     * @param key
     * @return
     * @throws IllegalArgumentException
     */
    public static Algorithm HMAC256(byte[] secret) throws IllegalArgumentException {
        return new HMACAlgorithm("HS256", "HmacSHA256", secret);
    }

    /**
     * HS384 算法
     * @param key
     * @return
     * @throws IllegalArgumentException
     */
    public static Algorithm HMAC384(byte[] secret) throws IllegalArgumentException {
        return new HMACAlgorithm("HS384", "HmacSHA384", secret);
    }

    /**
     * HS512 算法
     * @param key
     * @return
     * @throws IllegalArgumentException
     */
    public static Algorithm HMAC512(byte[] secret) throws IllegalArgumentException {
        return new HMACAlgorithm("HS512", "HmacSHA512", secret);
    }

    /**
     * ES256 算法
     * @param key
     * @return
     * @throws IllegalArgumentException
     */
    public static Algorithm ECDSA256(ECKey key) throws IllegalArgumentException {
        return new ECDSAAlgorithm("ES256", "SHA256withECDSA", 32, key);
    }

    /**
     * ES384 算法
     * @param key
     * @return
     * @throws IllegalArgumentException
     */
    public static Algorithm ECDSA384(ECKey key) throws IllegalArgumentException {
        return new ECDSAAlgorithm("ES384", "SHA384withECDSA", 48, key);
    }

    /**
     * ES512 算法
     * @param key
     * @return
     * @throws IllegalArgumentException
     */
    public static Algorithm ECDSA512(ECKey key) throws IllegalArgumentException {
        return new ECDSAAlgorithm("ES512", "SHA512withECDSA", 66, key);
    }

    public static Algorithm none() {
        return new NoneAlgorithm();
    }

    protected Algorithm(String name, String description) {
        this.name = name;
        this.description = description;
    }

    public String getName() {
        return name;
    }

    String getDescription() {
        return description;
    }

    @Override
    public String toString() {
        return description;
    }

    /**
     * 验证token
     */
    public abstract void verify(byte[] contentBytes, byte[] signatureBytes) throws SignatureVerificationException;

    /**
     * 签名
     */
    public abstract byte[] sign(byte[] contentBytes) throws SignatureGenerationException;
}
